﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using WodLib.Tools;

namespace WodManager
{
    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();
        }

        //database where objects will be stored in memory during runtime
        private WodLib.Tools.WodObjectDatabase woddatabase = new WodLib.Tools.WodObjectDatabase();

        //perspective manager which helps switching between tabs
        private Funcionality.PerspectiveManager perspectiveManger = null;

        private Tools.ToolActivator toolActivator = null;

        private void FormMain_Load(object sender, EventArgs e)
        {
            wodObjectBindingSource.DataSource = woddatabase.ObjectsList;
            woddatabase.ReferenceChanged += new EventHandler<WodLib.Tools.WodObjectDatabase.ReferenceChangedEventArgs>(woddatabase_ReferenceChanged);
            toolActivator = new WodManager.Tools.ToolActivator(wodObjectBindingSource);

            //find aviable types and load them in combo boxes
            WodLib.Tools.HierarchicalTypeFinder htf = 
                new WodLib.Tools.HierarchicalTypeFinder();
            htf.FindTypes(typeof(WodLib.DimensionalObject));
            foreach (var item in htf.TypesFound)
            {
                if (!item.IsAbstract)
                    typeManagementBindingSource.Add(item); //to add management
                typeFilterBindingSource.Add(item); //to type filter
            }

            //fill comboboxes
            comboBoxAgainRule.DataSource = Enum.GetValues(
                typeof(WodLib.Tools.SuccessCalculator.AgainRule));
            comboBoxAgainRuleSimulation.DataSource = Enum.GetValues(
                typeof(WodLib.Tools.SuccessCalculator.AgainRule));

            comboBoxInputLength.DataSource = Enum.GetValues(
                typeof(WodLib.Tools.TraitsCalculator.LengthUnit));
            comboBoxInputSpeed.DataSource = Enum.GetValues(
                typeof(WodLib.Tools.TraitsCalculator.SpeedUnit));
            comboBoxOutputLength.DataSource = Enum.GetValues(
                typeof(WodLib.Tools.TraitsCalculator.LengthUnit));
            comboBoxOutputSpeed.DataSource = Enum.GetValues(
                typeof(WodLib.Tools.TraitsCalculator.SpeedUnit));
            comboBoxSpellDurationType.DataSource = Enum.GetValues(
                typeof(WodLib.Tools.MageSpellInfo.DurationType));
            comboBoxSpellRange.DataSource = Enum.GetValues(
                typeof(WodLib.Tools.MageSpellInfo.Range));

            foreach (var item in Enum.GetValues(typeof(WodLib.Config.Perspectives)))
            {
                toolStripComboBoxPerspective.Items.Add( ((WodLib.Config.Perspectives)item).ToString());
            }
            toolStripComboBoxPerspective.SelectedIndex = 0;

            perspectiveManger = new WodManager.Funcionality.PerspectiveManager(tabControlMain);
            perspectiveManger.SetPerspectiveTabs(WodLib.Config.Perspectives.WorldOfDarkness,
                new TabPage[] { tabPageFight, tabPageNotepad, tabPageUsefulTools });
            perspectiveManger.SetPerspectiveTabs(WodLib.Config.Perspectives.MageTheAwakening,
                new TabPage[] { tabPageSpellCalc });

        }

        void woddatabase_ReferenceChanged(object sender, WodLib.Tools.WodObjectDatabase.ReferenceChangedEventArgs e)
        {
            wodObjectBindingSource.DataSource = e.NewObjectsList;
        }

        private void buttonAdd_Click(object sender, EventArgs e)
        {
            WodLib.WodObject newObj = (WodLib.WodObject)
                Activator.CreateInstance((Type)typeManagementBindingSource.Current);
            newObj.Name = "--new " + typeManagementBindingSource.Current.ToString();
            wodObjectBindingSource.Add(newObj);
        }

        private void wodObjectBindingSource_CurrentChanged(object sender, EventArgs e)
        {
            propertyGridMain.SelectedObject = wodObjectBindingSource.Current;
            WodLib.WodObject wodobj = ((WodLib.WodObject)wodObjectBindingSource.Current);
            animalAttackQuickInfoMain.Actor = wodobj;
            if (wodobj != null)
            {

                labelQuickType.Text = wodobj.GetType().ToString();
                if (wodobj.Description != null)
                {
                    labelDescription.Text = string.Join(Environment.NewLine, wodobj.Description);
                }
                else
                {
                    labelDescription.Text = "";
                }
            }
            else
            {
                labelQuickType.Text = "Nothing seleted";
            }
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialogMain.ShowDialog() == DialogResult.OK)
            {
                woddatabase.DeserializeFromFile(openFileDialogMain.FileName);
                //wodObjectBindingSource.DataSource = woddatabase.ObjectsList;
            }
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (System.IO.File.Exists(saveFileDialogMain.FileName))
            {
                woddatabase.SerializeToFile(saveFileDialogMain.FileName);
            }
            else if (System.IO.File.Exists(openFileDialogMain.FileName))
            {
                woddatabase.SerializeToFile(openFileDialogMain.FileName);
            }
            else if (saveFileDialogMain.ShowDialog() == DialogResult.OK)
            {
                woddatabase.SerializeToFile(saveFileDialogMain.FileName);
            }
        }

        private void buttonDelete_Click(object sender, EventArgs e)
        {
            wodObjectBindingSource.RemoveCurrent();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            woddatabase.ObjectsList = new List<WodLib.WodObject>();
        }

        private void toolStripMenuItemPaste_Click(object sender, EventArgs e)
        {
            wodObjectBindingSource.Add(WodLib.Tools.WodObjectClipboard.Paste());
        }

        private void toolStripMenuItemCopy_Click(object sender, EventArgs e)
        {
            WodLib.Tools.WodObjectClipboard.Copy((WodLib.WodObject)wodObjectBindingSource.Current);
        }

        private void toolStripMenuItemCut_Click(object sender, EventArgs e)
        {
            toolStripMenuItemCopy_Click(sender, e);
            wodObjectBindingSource.RemoveCurrent();
        }

        private void buttonInitiativeAdd_Click(object sender, EventArgs e)
        {
            if (wodObjectBindingSource.Current is WodLib.Being)
            {
                if (!beingBindingSource.Contains(wodObjectBindingSource.Current))
                {
                    beingBindingSource.Add(wodObjectBindingSource.Current);
                }
            }            
        }

        private void buttonInitiativeRemove_Click(object sender, EventArgs e)
        {
            if (beingBindingSource.Current != null)
            {
                beingBindingSource.RemoveCurrent();
            }
        }

        private void buttonInitiativeUp_Click(object sender, EventArgs e)
        {
            //beingBindingSource.SuspendBinding();
            object current = beingBindingSource.Current;
            int currentPos = beingBindingSource.Position;
            beingBindingSource.RemoveCurrent();
            currentPos--;
            if (currentPos > beingBindingSource.List.Count)
	        {
                currentPos = beingBindingSource.List.Count;
	        }
            else if (currentPos < 0)
            {
                currentPos = 0;
            }
            beingBindingSource.List.Insert(currentPos, current);
            beingBindingSource.Position = currentPos;
            //beingBindingSource.ResumeBinding();

        }

        private void buttonInitiativeDown_Click(object sender, EventArgs e)
        {
            //beingBindingSource.SuspendBinding();
            object current = beingBindingSource.Current;
            int currentPos = beingBindingSource.Position;
            beingBindingSource.RemoveCurrent();
            currentPos++;
            if (currentPos > beingBindingSource.List.Count)
            {
                currentPos = beingBindingSource.List.Count;
            }
            else if (currentPos < 0)
            {
                currentPos = 0;
            }
            beingBindingSource.List.Insert(currentPos, current);
            beingBindingSource.Position = currentPos;
            //beingBindingSource.ResumeBinding();
        }

        private void buttonIntiativeClear_Click(object sender, EventArgs e)
        {
            beingBindingSource.Clear();
        }

        private Funcionality.Notepad notepad = null;

        private void tabControlMain_Selecting(object sender, TabControlCancelEventArgs e)
        {
            //create and load new notepad
            if (e.TabPage == tabPageNotepad && notepad == null)
            {
                notepad = new WodManager.Funcionality.Notepad();
#if !DEBUG
                notepad.DeserializeFromXml(notepadFilePath);
#endif
                noteBindingSource.DataSource = notepad.Notes;
            }
        }

        private void buttonNoteAdd_Click(object sender, EventArgs e)
        {
            noteBindingSource.Add(new Funcionality.Note() { Title = comboBoxNotes.Text, 
                Content = textBoxNotepad.Text });
            textBoxNotepad.Text = ((Funcionality.Note)noteBindingSource.Current).Content;
        }

        private void buttonNoteRemove_Click(object sender, EventArgs e)
        {
            noteBindingSource.RemoveCurrent();
        }

        private void buttonSaveNotepad_Click(object sender, EventArgs e)
        {
            notepad.SerializeToXml(notepadFilePath);
        }

        private const string notepadFilePath = "notepad.xml";

        private void SaveNote()
        {
            if (noteBindingSource.Current != null)
            {
                ((Funcionality.Note)noteBindingSource.Current).Content =
                    string.Join("\n", textBoxNotepad.Lines);
                //textBoxNotepad.Text; 
            }
        }

        private void noteBindingSource_CurrentChanged(object sender, EventArgs e)
        {
            
        }

        private void buttonSaveNotepad_Click_1(object sender, EventArgs e)
        {
            SaveNote();
            notepad.SerializeToXml(notepadFilePath);
        }

        private void comboBoxNotes_SelectedIndexChanged(object sender, EventArgs e)
        {
            SaveNote();
        }

        private void noteBindingSource_PositionChanged(object sender, EventArgs e)
        {
            textBoxNotepad.Lines = ((Funcionality.Note)noteBindingSource.Current).Content.Split(
                new string[] {"\n"}, StringSplitOptions.RemoveEmptyEntries);
        }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
#if !DEBUG
            if (notepad != null)
            {
                notepad.SerializeToXml(notepadFilePath);
            }
#endif
        }

        private void buttonLoadNotepad_Click(object sender, EventArgs e)
        {
            notepad.DeserializeFromXml(notepadFilePath);
            textBoxNotepad.Lines = ((Funcionality.Note)noteBindingSource.Current).Content.Split(
                new string[] { "\n" }, StringSplitOptions.None);
        }

        private void buttonCalculate_Click(object sender, EventArgs e)
        {
            int dices;
            int.TryParse(textBoxCalcDices.Text, out dices);
            labelSuccessAvResult.Text =
                SuccessCalculator.CalculateAverageSucesses(
                    dices, (SuccessCalculator.AgainRule)Enum.Parse(typeof(WodLib.Tools.SuccessCalculator.AgainRule),
                    comboBoxAgainRule.Text)).ToString("F9");
                
        }

        private void toolStripMenuItemSaveAs_Click(object sender, EventArgs e)
        {
            if (saveFileDialogMain.ShowDialog() == DialogResult.OK)
            {
                woddatabase.SerializeToFile(saveFileDialogMain.FileName);
            }
        }

        private void buttonConvertLength_Click(object sender, EventArgs e)
        {
            double length = 0.0;
            double.TryParse(textBoxInputLength.Text, out length);
            Type enumType = typeof(WodLib.Tools.TraitsCalculator.LengthUnit);
            length = WodLib.Tools.TraitsCalculator.ConvertLength(
                length,
                (WodLib.Tools.TraitsCalculator.LengthUnit)Enum.Parse(enumType, comboBoxInputLength.Text),
                (WodLib.Tools.TraitsCalculator.LengthUnit)Enum.Parse(enumType, comboBoxOutputLength.Text));
            textBoxOutputLength.Text = length.ToString();
        }

        private void buttonConvertSpeed_Click(object sender, EventArgs e)
        {
            double speed = 0.0;
            double.TryParse(textBoxInputSpeed.Text, out speed);
            Type enumType = typeof(WodLib.Tools.TraitsCalculator.SpeedUnit);
            speed = WodLib.Tools.TraitsCalculator.ConvertSpeed(
                speed,
                (WodLib.Tools.TraitsCalculator.SpeedUnit)Enum.Parse(enumType, comboBoxInputSpeed.Text),
                (WodLib.Tools.TraitsCalculator.SpeedUnit)Enum.Parse(enumType, comboBoxOutputSpeed.Text));
            textBoxOutputSpeed.Text = speed.ToString();
        }

        private void wodObjectBindingSource_CurrentItemChanged(object sender, EventArgs e)
        {

        }

        private void propertyGridMain_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
        {
            propertyGridMain.Refresh();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show(Funcionality.VersionDetails.GetVersionDetails(),
                "Version info");
        }

        private void openMainPageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start(@"QuickReference\index.html");
        }

        private void buttonSimulateDice_Click(object sender, EventArgs e)
        {
            long diceCount = 0;
            long.TryParse(textBoxDiceCount.Text, out diceCount);
            long againFrom = 0;
            WodLib.Tools.SuccessCalculator.AgainRule againRule =
                (WodLib.Tools.SuccessCalculator.AgainRule)
                Enum.Parse(typeof(WodLib.Tools.SuccessCalculator.AgainRule), comboBoxAgainRuleSimulation.Text);
            againFrom = (long)againRule;

            labelSimulationDiceResult.Text = 
                WodLib.Tools.DiceRollSimulator.CalculateAverageSuccesses(diceCount, againFrom).ToString();
                
        }

        private void listBoxObjects_DragOver(object sender, DragEventArgs e)
        {

        }

        private void radioButtonSpellIsAoe_CheckedChanged(object sender, EventArgs e)
        {
            numericUpDownSpellNumberOfTargets.Enabled = false;
            labelSpellAreaOrSize.Text = "Radius:";
        }

        private void radioButtonSpellIsTargeted_CheckedChanged(object sender, EventArgs e)
        {
            numericUpDownSpellNumberOfTargets.Enabled = true;
            labelSpellAreaOrSize.Text = "Size:";
        }

        private WodLib.Mage caster = null;

        private void buttonCasterConnect_Click(object sender, EventArgs e)
        {
            if (wodObjectBindingSource.Current is WodLib.Mage)
            {
                caster = (WodLib.Mage)wodObjectBindingSource.Current;
                labelCasterName.Text = caster.Name;
                numericUpDownNeededMana.Maximum = Math.Min(caster.ManaPerTurn, caster.Mana);
                textBoxCasterAviableMana.Text = numericUpDownNeededMana.Maximum.ToString();
            }
        }

        private void buttonCasterClear_Click(object sender, EventArgs e)
        {
            caster = null;
            labelCasterName.Text = "---";
        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {

        }

        private MageSpellInfo MageSpellInfoFromInterface()
        {
            WodLib.Tools.MageSpellInfo spellInfo = new MageSpellInfo
            {
                Advanced = checkBoxAdvancedVersion.Checked,
                AimedSpellPenalty = (int)numericUpDownAimedPenalty.Value,
                BaseDicePool = (int)numericUpDownBaseDicePool.Value,
                CultOrOcultPenalty = (int)numericUpDownCultPenalty.Value,
                Duration = (int)numericUpDownSpellDuration.Value,
                IsAreaAffecting = radioButtonSpellIsAoe.Checked,
                NumberOfTargets = (int)numericUpDownSpellNumberOfTargets.Value,
                Potency = (int)numericUpDownSpellPotency.Value,
                SizeOrArea = (int)numericUpDownSizeOrArea.Value,
                SympatheticRange = (MageSpellInfo.Range)Enum.Parse(typeof(MageSpellInfo.Range), comboBoxSpellRange.Text),
                TypeOfDuration = (MageSpellInfo.DurationType)Enum.Parse(typeof(MageSpellInfo.DurationType), comboBoxSpellDurationType.Text),
                UseAtlanteanRunes = checkBoxAtlanteanRunes.Checked,
                UseWordsOfPower = checkBoxWordsOfPower.Checked
            };
            return spellInfo;
        }

        private void buttonCastSpell_Click(object sender, EventArgs e)
        {
            TextBox output = textBoxSpellResults;
            if (caster == null)
            {
                output.Text = "Caster not selected";
                return;
            }
            WodLib.Tools.MageSpellInfo spellInfo = MageSpellInfoFromInterface();

            var calc = new MageSpellCalculator();
            calc.Caster = caster;
            output.Text = calc.CastSpell(
                spellInfo, (int)numericUpDownParadoxSuccesses.Value, radioButtonSpellExtended.Checked,
                (int)numericUpDownNeededMana.Value
                ).ToString();

            numericUpDownNeededMana.Maximum = Math.Min(caster.ManaPerTurn, caster.Mana);
            textBoxCasterAviableMana.Text = numericUpDownNeededMana.Maximum.ToString();
        }

        private void radioButtonSpellInstant_CheckedChanged(object sender, EventArgs e)
        {
            groupBoxSpellBasePool.Enabled = true;
        }

        private void radioButtonSpellExtended_CheckedChanged(object sender, EventArgs e)
        {
            groupBoxSpellBasePool.Enabled = false;
        }

        private void buttonSpellCalculate_Click(object sender, EventArgs e)
        {
            TextBox output = textBoxSpellResults;
            if (caster == null)
            {
                output.Text = "Cannot cast spell, no caster selected";
            }
            WodLib.Tools.MageSpellInfo spellInfo = MageSpellInfoFromInterface();

            var calc = new MageSpellCalculator();
            calc.Caster = caster;
            output.Text = calc.CalculateSpell(
                spellInfo, (int)numericUpDownParadoxSuccesses.Value, radioButtonSpellExtended.Checked
                ).ToString();

            
        }

        private void comboBoxSpellDurationType_SelectedIndexChanged(object sender, EventArgs e)
        {
            MageSpellInfo.DurationType duration =
                Funcionality.EnumParser<MageSpellInfo.DurationType>.ParseString(comboBoxSpellDurationType.Text);
            Label label = labelSpellDurationUnits;
            NumericUpDown updown = numericUpDownSpellDuration;
            switch (duration)
            {
                case MageSpellInfo.DurationType.Lasting:
                    label.Text = "";
                    updown.Enabled = false;
                    break;
                case MageSpellInfo.DurationType.Concentration:
                    label.Text = "";
                    updown.Enabled = false;
                    break;
                case MageSpellInfo.DurationType.Transistory:
                    label.Text = "turn";
                    updown.Enabled = true ;
                    break;
                case MageSpellInfo.DurationType.Prolonged:
                    label.Text = "hour";
                    updown.Enabled = true;
                    break;
                default:
                    break;
            }
        }

        private void toolStripMenuItemImport_Click(object sender, EventArgs e)
        {
            if (openFileDialogImport.ShowDialog() == DialogResult.OK)
            {
                if (System.IO.File.Exists(openFileDialogImport.FileName))
                {
                    woddatabase.ImportFromFile(openFileDialogImport.FileName);
                    wodObjectBindingSource.ResetBindings(false);
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            tabControlMain.TabPages.Remove(tabPageSpellCalc);
            tabControlMain.TabPages.Add(tabPageSpellCalc);
        }

        private void toolStripComboBoxPerspective_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (perspectiveManger == null)
                return;

            var perspective = Funcionality.EnumParser<WodLib.Config.Perspectives>.ParseString(
                toolStripComboBoxPerspective.Text);

            perspectiveManger.ChangePerspective(perspective);
        }

        private void editAsAnimalToolStripMenuItem_Click(object sender, EventArgs e)
        {
            toolActivator.ActivateFormModal(new WodManager.Tools.AnimalEditor());
        }

        private void editAsAnimalToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {

        }

        private void toolsToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            editAsAnimalToolStripMenuItem.Enabled =
                (wodObjectBindingSource.Current is WodLib.Animal);
        }
    }
}
